/*
 * Copyright (c) 2025 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include "mcpy/builtins/list.h"
#include "mcpy/exception.h"
#include <cstdint>

namespace mcpy {

mc::variant_reference list_getitem(mc::variants& container, int index) {
    int size = static_cast<int>(container.size());
    if (index < 0) {
        index += size;
    }
    if (index < 0 || index >= size) {
        MC_THROW(mcpy::index_error, "list index out of range");
    }
    return container[static_cast<size_t>(index)];
}

mc::variant list_getitem(const mc::variants& container, int index) {
    int size = static_cast<int>(container.size());
    if (index < 0) {
        index += size;
    }
    if (index < 0 || index >= size) {
        MC_THROW(mcpy::index_error, "list index out of range");
    }
    return container[static_cast<size_t>(index)];
}

void list_setitem(mc::variants& container, int index, const mc::variant& value) {
    int size = static_cast<int>(container.size());
    if (index < 0) {
        index += size;
    }
    if (index < 0 || index >= size) {
        MC_THROW(mcpy::index_error, "list assignment index out of range");
    }
    container.set(static_cast<size_t>(index), value);
}

mc::variant list_pop_back(mc::variants& container) {
    if (container.empty()) {
        MC_THROW(mcpy::index_error, "pop from empty list");
    }
    mc::variant value = container[container.size() - 1];
    container.pop_back();
    return value;
}

mc::variant list_pop(mc::variants& container, size_t index) {
    if (index >= container.size()) {
        MC_THROW(mcpy::index_error, "pop index out of range");
    }
    mc::variant value = container[index];
    container.erase(container.begin() + index);
    return value;
}

void list_remove(mc::variants& container, const mc::variant& item) {
    auto it = std::find(container.begin(), container.end(), item);
    if (it == container.end()) {
        MC_THROW(mcpy::value_error, "list.remove(x): x not in list");
    }
    container.erase(it);
}

// 切片辅助函数：规范化切片索引
// 处理负索引、None 值和边界调整，完全遵循 Python 语义
void normalize_slice_indices(
    int64_t  size,
    int64_t* start,
    int64_t* stop,
    int64_t  step) {
    // step 不能为 0
    if (step == 0) {
        MC_THROW(mcpy::value_error, "slice step cannot be zero");
    }

    // 处理负索引
    auto normalize_index = [size](int64_t idx, int64_t default_val) -> int64_t {
        if (idx < 0) {
            idx += size;
        }
        return idx;
    };

    // 根据 step 的符号确定默认值
    int64_t default_start = (step > 0) ? 0 : size - 1;
    int64_t default_stop  = (step > 0) ? size : -1;

    // 规范化 start
    int64_t norm_start = (*start == INT64_MIN) ? default_start : normalize_index(*start, default_start);

    // 规范化 stop
    int64_t norm_stop = (*stop == INT64_MIN) ? default_stop : normalize_index(*stop, default_stop);

    // 调整边界（Python 切片不会抛出 IndexError）
    if (step > 0) {
        // 正向切片
        if (norm_start < 0) {
            norm_start = 0;
        }
        if (norm_start > size) {
            norm_start = size;
        }
        if (norm_stop < 0) {
            norm_stop = 0;
        }
        if (norm_stop > size) {
            norm_stop = size;
        }
    } else {
        // 反向切片
        if (norm_start < -1) {
            norm_start = -1;
        }
        if (norm_start >= size) {
            norm_start = size - 1;
        }
        if (norm_stop < -1) {
            norm_stop = -1;
        }
        if (norm_stop >= size) {
            norm_stop = size - 1;
        }
    }

    *start = norm_start;
    *stop  = norm_stop;
}

// ============================================================================
// 显式实例化常用类型，减少代码膨胀
// ============================================================================

// int 类型
MC_LIST_TEMPLATE(template MC_API, int)
MC_LIST_TEMPLATE(template MC_API, double)
MC_LIST_TEMPLATE(template MC_API, std::string)

MC_LIST_VARIANTS_TEMPLATE(template MC_API)

} // namespace mcpy
